package com.ktg.ktgcommon.filter;


import com.ktg.ktgcommon.constant.Constants;
import com.ktg.ktgcommon.domain.user.SysUser;
import com.ktg.ktgcommon.result.CodeEnum;
import com.ktg.ktgcommon.result.R;
import com.ktg.ktgcommon.service.RedisService;
import com.ktg.ktgcommon.utils.JSONUtils;
import com.ktg.ktgcommon.utils.JWTUtils;
import com.ktg.ktgcommon.utils.ResponseUtils;
import jakarta.annotation.Resource;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.TimeUnit;


@Component
public class TokenVerifyFilter extends OncePerRequestFilter {
    public static String redisJwt;
    @Resource   
    private RedisService redisService;
    //springBoot框架中的ioc容器已经创建好了线程池，可以直接注入使用
    @Resource
    private ThreadPoolTaskExecutor threadPoolTaskExecutor;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        response.setContentType("application/json");
        System.out.println(request.getRequestURI());
        Set<String> excludes = new HashSet<>();
        excludes.add(request.getContextPath() + Constants.LOGIN_URI);
        if (excludes.contains(request.getRequestURI())){ //如果是登录请求，此时还没有生成jwt，那不需要对登录请求进行jwt验证

            filterChain.doFilter(request, response);
        } else {

            String jwt = request.getHeader("dlyk_token");
            if (!StringUtils.hasText(jwt)) {

                //登录成功的统一结果
                R result = R.FAIL(CodeEnum.LOGIN_JWT_IS_EMPTY);

                //把R对象转成json
                String resultJSON = JSONUtils.toJSON(result);

                //把R以json返回给前端
                ResponseUtils.write(response, resultJSON);

                return;
            }
            if(!JWTUtils.verifyJWT(jwt)){
                R result = R.FAIL(CodeEnum.LOGIN_JWT_IS_ERROR);

                //把R对象转成json
                String resultJSON = JSONUtils.toJSON(result);

                //把R以json返回给前端
                ResponseUtils.write(response, resultJSON);

                return;
            }
            SysUser tUser = null;
            try{
                tUser = JWTUtils.parseUserFromJWT(jwt);
            }catch (Exception e){
                e.printStackTrace();
            }

            if(tUser == null){
                R result = R.FAIL(CodeEnum.LOGIN_JWT_IS_ERROR);

                //把R对象转成json
                String resultJSON = JSONUtils.toJSON(result);

                //把R以json返回给前端
                ResponseUtils.write(response, resultJSON);

                return;
            }

            redisJwt= (String) redisService.getValue(Constants.REDIS_JWT_KEY + tUser.getUserId());

            if (!StringUtils.hasText(redisJwt)) {
                //登录成功的统一结果
                R result = R.FAIL(CodeEnum.LOGIN_JWT_IS_EXPIRE);
                //把R对象转成json
                String resultJSON = JSONUtils.toJSON(result);
                //把R以json返回给前端
                ResponseUtils.write(response, resultJSON);
                return;
            }
            if (!jwt.equals(redisJwt)) {
                //登录成功的统一结果
                R result = R.FAIL(CodeEnum.LOGIN_JWT_IS_ERROR);

                //把R对象转成json
                String resultJSON = JSONUtils.toJSON(result);

                //把R以json返回给前端
                ResponseUtils.write(response, resultJSON);
                return;
            }
            final SysUser innerUser = tUser;
            //jwt验证通过了，那么在spring security的上下文环境中要设置一下，设置当前这个人是登录过的，你后续不要再拦截他了
            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(tUser, tUser.getPassword(), tUser.getAuthorities());
            SecurityContextHolder.getContext().setAuthentication(authenticationToken);
            //刷新token(异步处理)
            threadPoolTaskExecutor.execute(()->{
                String rememberMe=request.getHeader("rememberMe");
                if (Boolean.parseBoolean(rememberMe)) {
                    redisService.expire(Constants.REDIS_JWT_KEY+innerUser.getUserId(),Constants.EXPIRE_TIME, TimeUnit.MINUTES);
                }else {
                    redisService.expire(Constants.REDIS_JWT_KEY+innerUser.getUserId(),Constants.DEFAULT_EXPIRE_TIME, TimeUnit.MINUTES);
                }
            });
            //验证jwt通过了 ，让Filter链继续执行，也就是继续执行下一个Filter
            filterChain.doFilter(request, response);
        }
    }
    public static SysUser getUserName(){
        return JWTUtils.parseUserFromJWT(redisJwt);
    }
}
